package org.vacoor.xqq.core.mod;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.xqq.core.bean.Category;
import org.vacoor.xqq.core.bean.ChatToken;
import org.vacoor.xqq.core.bean.Contact;
import org.vacoor.xqq.core.http.HttpRequestor;
import org.vacoor.xqq.core.http.Request;
import org.vacoor.xqq.core.http.RequestCallbackAdapter;
import org.vacoor.xqq.core.http.Response;
import org.vacoor.xqq.core.msg.eventmsg.StatusChangeMsg;
import org.vacoor.xqq.core.msg.resp.AvatarMessage;
import org.vacoor.xqq.core.msg.EventBusHolder;
import org.vacoor.xqq.core.msg.resp.LongNickMessage;
import org.vacoor.xqq.core.msg.resp.FriendsRs;
import org.vacoor.xqq.core.msg.resp.ResponseMsg;
import org.vacoor.xqq.core.util.Jacksons;
import org.vacoor.xqq.core.util.QQUtil;
import org.vacoor.xqq.core.util.Regexs;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * User: vacoor
 *
 * 先加载缓存, 如果缓存不存在, 则使用默认头像, 然后去加载头像并存入缓存, 头像更新在每次状态改变
 */
public class BuddyManager {
    private static final Logger logger = LoggerFactory.getLogger(BuddyManager.class);

    public static final String GET_CONTACTS_URL = "http://s.web2.qq.com/api/get_user_friends2";
    public static final String GET_ONLINE_CONTACTS_URL = "http://d.web2.qq.com/channel/get_online_buddies2";
    public static final String GET_PERSINAL_MSG_URL = "http://s.web2.qq.com/api/get_single_long_nick2";
    public static final String GET_ACCOUNT = "http://s.web2.qq.com/api/get_friend_uin2";
    public static final String REFERER = "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=3";
    private ChatToken token;

    Map<Integer, Category> categories = new LinkedHashMap<Integer, Category>();
    Map<Long, Contact> contacts = new LinkedHashMap<Long, Contact>();

    public BuddyManager(ChatToken token) {
        this.token = token;
    }

    /**
     * 获取分组和基本好友信息
     *
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws IOException
     */
    public Set<Category> getContacts() throws ExecutionException, InterruptedException, IOException {
        String hash = QQUtil.hash(token.getUin(), token.getPtwebqq());

        String param = Jacksons.createObjectNode().put("vfwebqq", token.getVfwebqq()).put("hash", hash).toString();
        logger.debug("getContacts : {}", param);

        Response resp = HttpRequestor.getInstance().send(
                new Request(GET_CONTACTS_URL, Request.HttpMethod.POST)
                        .addHeader("MsgBody-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                        .addHeader("Referer", REFERER)
                        .addParameter("r", param),

                null).get();

        String s = resp.getContent().asString();
        logger.debug("获取好友列表, 响应: {}", s);
        ResponseMsg<FriendsRs> res = Jacksons.deserialize(s, new TypeReference<ResponseMsg<FriendsRs>>() {});

        // ------------------------------------
        FriendsRs friendsRs = res.getResult();
        processContacts(friendsRs);

        // 排序返回
        return new TreeSet<Category>(categories.values());
    }

    public Contact getContact(long uin) {
        return contacts.get(uin);
    }

    public Category getCategory(int index) {
        return categories.get(index);
    }

    private void processContacts(FriendsRs friendsRs) {
        // 遍历分组
        for (FriendsRs.CategoryDTO c : friendsRs.getCategories()) {
            Category category = new Category(c.getIndex(), c.getName());
            categories.put(c.getIndex(), category);
        }

        // 遍历所有基本好友信息
        for (FriendsRs.BasicFriendInfoDTO bfi : friendsRs.getInfo()) {
            Long uin = bfi.getUin();
            String nick = bfi.getNick();
            if (null == contacts.get(uin)) {
                Contact contact = new Contact();
                contact.setId(uin);
                contact.setNick(nick);
                contacts.put(uin, contact);
            }
        }

        // 遍历所有好友别名
        for (FriendsRs.FriendMarknameDTO fm : friendsRs.getMarknames()) {
            Contact contact = contacts.get(fm.getUin());
            if (contact == null) {
                continue;
            }
            contact.setMark(fm.getMarkname());
        }

        // 遍历所有好友分组信息
        for (FriendsRs.CategoryFriendDTO cf : friendsRs.getFriends()) {
            Category category = categories.get(cf.getCategory());
            if (category == null) {
                if (0 == cf.getCategory()) {
                    category = new Category();
                    category.setIndex(0);
                    category.setName("我的好友");
                    categories.put(0, category);
                }
            }
            Contact contact = contacts.get(cf.getUin());
            if(contact != null) {
                contact.setCategory(category);
                category.getContacts().add(contact);
            }
        }
    }

    // {
    // "retcode":0,
    // "result":[
    //      {"uin":3229168883,"status":"callme","client_type":41},
    //      {"uin":41732157,"status":"online","client_type":21},
    //      {"uin":1424619472,"status":"online","client_type":24}
    // ]
    // }

    /**
     * 该方法应该在所有监听初始化后调用
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws IOException
     */
    public void getOnlineContacts() {
        // clientId, psessionId, ui
        Future<Response> send = HttpRequestor.getInstance().send(
                new Request(GET_ONLINE_CONTACTS_URL, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("clientid", token.getClientId())
                        .addParameter("psessionid", token.getPsessionId())
                        .addParameter("ui", new Date().getTime()),
                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) throws IOException {
                        JsonNode root = Jacksons.readTree(resp.getContent().asString());
                        int retcode = root.get("retcode").asInt(1);
                        if(0 == retcode) {
                            StatusChangeMsg[] results = Jacksons.deserialize(root.get("result").toString(), StatusChangeMsg[].class);
                            for(StatusChangeMsg scm : results) {
//                                logger.info("获取在线状态: {}", scm);
                                EventBusHolder.getEventBus().post(scm);
                            }
                        }
                    }
                }
        );
//        String s = send.get().getMsgBody().asString();
//        logger.debug("Online Contacts: {}", s);
//        return Regexs.grep(s, "\"account\":([0-9]+)")[0][1];
    }


    /**
     * 获取显示的账户
     * 获取好友qq帐号
     * 1 好友, 4 群
     *
     * @param uin
     * @param type
     * @return
     * @throws java.util.concurrent.ExecutionException
     *
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public String getAccount(long uin, int type) throws ExecutionException, InterruptedException, IOException {
        Future<Response> send = HttpRequestor.getInstance().send(
                new Request(GET_ACCOUNT, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("tuin", uin + "")
                        .addParameter("verifysession", "")
                        .addParameter("type", type + "")
                        .addParameter("code", "")
                        .addParameter("vfwebqq", token.getVfwebqq())
                        .addParameter("ui", new Date().getTime()),
                null
        );
        String s = send.get().getContent().asString();
        return Regexs.grep(s, "\"account\":([0-9]+)")[0][1];
    }

    // 个性签名
    // {"retcode":0,"result":[{"uin":4156523229,"lnick":"__硪 锝 幸 福 、与 爱 情 无 关 、（却） 与 迩 冇 关"}]}
    public void getPersionalMsg(long uin) {
        HttpRequestor.getInstance().send(
                new Request(GET_PERSINAL_MSG_URL, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("tuin", uin)
                        .addParameter("vfwebqq", token.getVfwebqq())
                        .addParameter("ui", Math.random()),
                null
        );
    }

    public void getPersionalMsgAsync(long uin) {
        HttpRequestor.getInstance().send(
                new Request(GET_PERSINAL_MSG_URL, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("tuin", uin)
                        .addParameter("vfwebqq", token.getVfwebqq())
                        .addParameter("ui", Math.random()),
                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) throws IOException {
                        JsonNode root = Jacksons.readTree(resp.getContent().asString());
                        int retcode = root.get("retcode").asInt(1);
                        if( 0 == retcode ) {
                            LongNickMessage[] results = Jacksons.deserialize(root.get("result").toString(), LongNickMessage[].class);
                            for(LongNickMessage lnm : results) {
                                EventBusHolder.getEventBus().post(lnm);
                            }
                        }
                    }
                }
        );
    }

    /**
     * 该方法用于异步加载头像(加载头像比较耗时)
     * 当指定使用Cache时, 会先从Cache中加载, 如果Cache不存在,则从网络中下载
     * 之后会派发 {@link AvatarMessage}
     * @param uin
     * @param type
     * @param cache
     */
    public void loadAvatar(final long uin, final int type, final boolean cache) {
        throw new UnsupportedOperationException("该方法暂时未完善");
        /*
        byte[] bytes = null;
        if(cache) {
//            ImageIO.read("")
        }
        if(bytes == null) {

        }

        // 这里是不是该加个类型
        EventBusHolder.getEventBus().post(new AvatarMessage(uin, bytes));
        */
    }
    //public static final String AVATAR_URL = "http://face8.web.qq.com/cgi/svr/face/getface";
    // http://face8.web.qq.com/cgi/svr/face/getface?cache=1&type=1&f=40&uin=2213328508&ui=&vfwebqq=
    public byte[] getAvatar(long uin, int type) throws ExecutionException, InterruptedException, IOException {
        // 这里face8 8 = uin % 10, 但是不高也可
        final String AVATAR_URL = "http://face" + uin % 10 + ".web.qq.com/cgi/svr/face/getface";
        Response response = HttpRequestor.getInstance().send(
                new Request(AVATAR_URL, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("cache", "1")
                        .addParameter("type", type)
                        .addParameter("f", "40")
                        .addParameter("uin", uin)
                        .addParameter("ui", Math.random())
                        .addParameter("vfwebqq", token.getVfwebqq()),
                null
        ).get();
        return response.getContent().asBytes();
    }

    public static int getCount = 0;
    public static int okCount = 0;

    public void getAvatarAsync(final long uin, final int type) {
        // 这里face8 8 = uin % 10, 但是不搞也可
        final String AVATAR_URL = "http://face" + uin % 10 + ".web.qq.com/cgi/svr/face/getface";
        // http://face7.web.qq.com/cgi/svr/face/getface?cache=1&type=11&fid=0&uin=272451590&vfwebqq=0c0159e1732b590c4dacc0ca9509b355527d7efe933a7340df1413a2e65dea8338fd1322578aad3a&t=1382693721272
//        final String AVATAR_URL = "http://face8.web.qq.com/cgi/svr/face/getface";
        HttpRequestor.getInstance().send(
                new Request(AVATAR_URL, Request.HttpMethod.GET)
                        .addHeader("Referer", REFERER)
                        .addParameter("cache", "0")
                        .addParameter("type", type) // 11?,0
                        .addParameter("f", "40")    //0

//                        .addParameter("cache", "0")
//                        .addParameter("type", 11) // 11?,0
//                        .addParameter("f", "0")    //0

                        .addParameter("uin", uin)
                        .addParameter("ui", Math.random())
                        .addParameter("vfwebqq", token.getVfwebqq())
                        .addParameter("t", new Date().getTime()),
                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) throws IOException {
                        byte[] bytes = resp.getContent().asBytes();
//                        if(1560956957L == uin) {
//                            JOptionPane.showMessageDialog(null, "1560956957", "1560956957", JOptionPane.YES_OPTION, new ImageIcon(bytes));
//                        }
                        EventBusHolder.getEventBus().post(new AvatarMessage(uin, type, bytes));
                    }

                    @Override
                    public void onFailure(Response resp) {
                        logger.error("fail: {}", resp);
                        super.onFailure(resp);    //To change body of overridden methods use File | Settings | File Templates.
                    }

                    @Override
                    public void onException(Exception ex) {
                        logger.error("exception: {}", ex);
                        super.onException(ex);    //To change body of overridden methods use File | Settings | File Templates.
                    }
                }
        );
    }
}
